// 弹幕遮挡检测服务
import * as THREE from 'three';

export interface OcclusionResult {
    isOccluded: boolean;
    occlusionRatio: number; // 0-1，被遮挡的比例
    characterScreenPos?: { x: number; y: number; width: number; height: number };
}

export interface DanmuOcclusionConfig {
    checkInterval: number; // 检测间隔（毫秒）
    occlusionThreshold: number; // 遮挡阈值（0-1）
    debugMode: boolean; // 调试模式
    characterBounds: {
        width: number; // 人物在屏幕上的宽度比例
        height: number; // 人物在屏幕上的高度比例
        offsetY: number; // Y轴偏移（人物通常不在屏幕中心）
    };
}

const DEFAULT_CONFIG: DanmuOcclusionConfig = {
    checkInterval: 100, // 每100ms检测一次
    occlusionThreshold: 0.3, // 30%重叠就认为被遮挡
    debugMode: false,
    characterBounds: {
        width: 0.3, // 人物占屏幕宽度的30%
        height: 0.6, // 人物占屏幕高度的60%
        offsetY: 0.1, // 向下偏移10%
    }
};

class DanmuOcclusionService {
    private config: DanmuOcclusionConfig;
    private lastCheckTime: number = 0;
    private characterScreenBounds: { x: number; y: number; width: number; height: number } | null = null;
    private debugCanvas: HTMLCanvasElement | null = null;
    private debugCtx: CanvasRenderingContext2D | null = null;

    constructor(config: Partial<DanmuOcclusionConfig> = {}) {
        this.config = { ...DEFAULT_CONFIG, ...config };

        if (this.config.debugMode) {
            this.initDebugCanvas();
        }
    }

    // 初始化调试画布
    private initDebugCanvas(): void {
        this.debugCanvas = document.createElement('canvas');
        this.debugCanvas.style.position = 'fixed';
        this.debugCanvas.style.top = '0';
        this.debugCanvas.style.left = '0';
        this.debugCanvas.style.width = '100%';
        this.debugCanvas.style.height = '100%';
        this.debugCanvas.style.pointerEvents = 'none';
        this.debugCanvas.style.zIndex = '9999';
        this.debugCanvas.style.opacity = '0.5';

        document.body.appendChild(this.debugCanvas);
        this.debugCtx = this.debugCanvas.getContext('2d');

        // 监听窗口大小变化
        window.addEventListener('resize', () => {
            this.updateDebugCanvasSize();
        });

        this.updateDebugCanvasSize();
    }

    private updateDebugCanvasSize(): void {
        if (!this.debugCanvas) return;

        this.debugCanvas.width = window.innerWidth;
        this.debugCanvas.height = window.innerHeight;
    }

    // 更新人物在屏幕上的位置
    updateCharacterScreenPosition(
        characterWorldPosition: THREE.Vector3,
        camera: THREE.Camera,
        screenWidth: number,
        screenHeight: number
    ): void {
        try {
            // 将3D世界坐标投影到屏幕坐标
            const screenPosition = this.project3DToScreen(
                characterWorldPosition,
                camera,
                screenWidth,
                screenHeight
            );

            // 计算人物在屏幕上的边界框
            const bounds = this.config.characterBounds;
            this.characterScreenBounds = {
                x: screenPosition.x - (bounds.width * screenWidth) / 2,
                y: screenPosition.y - (bounds.height * screenHeight) / 2 + (bounds.offsetY * screenHeight),
                width: bounds.width * screenWidth,
                height: bounds.height * screenHeight,
            };

            // 调试模式下绘制人物边界
            if (this.config.debugMode && this.debugCtx) {
                this.drawDebugBounds();
            }
        } catch (error) {
            console.warn('更新人物屏幕位置失败:', error);
        }
    }

    // 3D坐标投影到屏幕坐标
    private project3DToScreen(
        worldPosition: THREE.Vector3,
        camera: THREE.Camera,
        screenWidth: number,
        screenHeight: number
    ): { x: number; y: number } {
        const vector = worldPosition.clone();
        vector.project(camera);

        // 转换为屏幕坐标
        const x = (vector.x * 0.5 + 0.5) * screenWidth;
        const y = (vector.y * -0.5 + 0.5) * screenHeight;

        return { x, y };
    }

    // 检测弹幕是否被遮挡
    checkDanmuOcclusion(
        danmuElement: HTMLElement,
        currentTime: number = performance.now()
    ): OcclusionResult {
        try {
            // 检查是否需要更新检测
            if (currentTime - this.lastCheckTime < this.config.checkInterval) {
                return this.getLastOcclusionResult();
            }

            this.lastCheckTime = currentTime;

            if (!this.characterScreenBounds || !danmuElement) {
                return { isOccluded: false, occlusionRatio: 0 };
            }

            // 获取弹幕元素在屏幕上的位置
            const danmuRect = danmuElement.getBoundingClientRect();

            // 计算重叠区域
            const overlap = this.calculateOverlap(
                danmuRect,
                this.characterScreenBounds
            );

            const occlusionRatio = overlap / (danmuRect.width * danmuRect.height);
            const isOccluded = occlusionRatio > this.config.occlusionThreshold;

            const result: OcclusionResult = {
                isOccluded,
                occlusionRatio,
                characterScreenPos: { ...this.characterScreenBounds }
            };

            // 调试模式下绘制弹幕边界
            if (this.config.debugMode && this.debugCtx) {
                this.drawDebugDanmu(danmuRect, isOccluded);
            }

            return result;
        } catch (error) {
            console.warn('弹幕遮挡检测失败:', error);
            return { isOccluded: false, occlusionRatio: 0 };
        }
    }

    // 计算两个矩形的重叠面积
    private calculateOverlap(
        rect1: DOMRect,
        rect2: { x: number; y: number; width: number; height: number }
    ): number {
        const left = Math.max(rect1.left, rect2.x);
        const right = Math.min(rect1.right, rect2.x + rect2.width);
        const top = Math.max(rect1.top, rect2.y);
        const bottom = Math.min(rect1.bottom, rect2.y + rect2.height);

        if (left < right && top < bottom) {
            return (right - left) * (bottom - top);
        }

        return 0;
    }

    // 获取上次检测结果（用于性能优化）
    private getLastOcclusionResult(): OcclusionResult {
        // 这里可以实现缓存机制，暂时返回简单结果
        return { isOccluded: false, occlusionRatio: 0 };
    }

    // 调试模式：绘制人物边界
    private drawDebugBounds(): void {
        if (!this.debugCtx || !this.characterScreenBounds) return;

        this.debugCtx.clearRect(0, 0, this.debugCanvas!.width, this.debugCanvas!.height);

        this.debugCtx.strokeStyle = 'red';
        this.debugCtx.lineWidth = 2;
        this.debugCtx.strokeRect(
            this.characterScreenBounds.x,
            this.characterScreenBounds.y,
            this.characterScreenBounds.width,
            this.characterScreenBounds.height
        );

        this.debugCtx.fillStyle = 'rgba(255, 0, 0, 0.1)';
        this.debugCtx.fillRect(
            this.characterScreenBounds.x,
            this.characterScreenBounds.y,
            this.characterScreenBounds.width,
            this.characterScreenBounds.height
        );
    }

    // 调试模式：绘制弹幕边界
    private drawDebugDanmu(danmuRect: DOMRect, isOccluded: boolean): void {
        if (!this.debugCtx) return;

        this.debugCtx.strokeStyle = isOccluded ? 'orange' : 'green';
        this.debugCtx.lineWidth = 1;
        this.debugCtx.strokeRect(
            danmuRect.left,
            danmuRect.top,
            danmuRect.width,
            danmuRect.height
        );
    }

    // 更新配置
    updateConfig(newConfig: Partial<DanmuOcclusionConfig>): void {
        this.config = { ...this.config, ...newConfig };

        if (newConfig.debugMode && !this.debugCanvas) {
            this.initDebugCanvas();
        } else if (!newConfig.debugMode && this.debugCanvas) {
            this.debugCanvas.remove();
            this.debugCanvas = null;
            this.debugCtx = null;
        }
    }

    // 清理资源
    destroy(): void {
        if (this.debugCanvas) {
            this.debugCanvas.remove();
            this.debugCanvas = null;
            this.debugCtx = null;
        }
    }

    // 获取当前配置
    getConfig(): DanmuOcclusionConfig {
        return { ...this.config };
    }
}

// 创建单例实例
export const danmuOcclusionService = new DanmuOcclusionService();
